#ifndef BASE_EVENT_H_
#define BASE_EVENT_H_

/*###################################################################*
#
# MP (Mitchell Pell) Base - CrossPlatform Base Utilities.
# Copyright (C) 2013  Mitchell Pell
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
####################################################################*/

#include <iostream>
#include <boost/shared_ptr.hpp>
#include "LockableMutex.h"
#include "Pause.h"

using std::ostream;
using std::istream;

namespace mp_base
{
	typedef unsigned int uint;
	typedef unsigned long ulong;
	/*!----------------------------------------------------------------
	*	@class		Event
	*	@brief		Template for an Event object.
	*
	*	@author		Mitchell Pell
	*	@date		11/05/2013
	*	@version	1.2
	*
	*	@revisions	Revision History:
	*
	*					- Version 1.2 11/05/2013
	*						-# Added the typedef shared_ptr<Event>
	*							!> Strongly recommended that this is 
	*								used instead of pointers.
	*						-# Added IOStream functionality
	*
	*					- Version 1.1 11/01/2013
	*						-# Added pre and post -- and ++ operators
	*						-# Added == and != operators
	*						-? Added target function handler for
	*							possible use.
	*
	*					- Version 1.0 09/27/2013
	*						-# Initial Make
	*
	-----------------------------------------------------------------*/
	class Event : public LockableMutex
	{
	public:
		typedef void(*HandlerFcn)(boost::shared_ptr<Event> evnt);

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		  >>  Constructors and Destructor
		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		/*! Default Constructor. */
		Event() : c_id(GetEventID())
			{ m_triggerCount = 0; 
			 m_targetFcn = NULL;}
		/*! Copy Constructor. */
		Event(const Event& evnt) : c_id(GetEventID())
			{m_triggerCount = evnt.m_triggerCount;
			 m_targetFcn = evnt.m_targetFcn;}
		/*! Destructor. */
		virtual ~Event(){}

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>  Event Triggering
		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		/*! Returns true on positive trigger count.  */
		virtual bool IsTriggered() const { return m_triggerCount > 0; }
		/*! Returns the actual trigger count. */
		uint TriggerCount() const { return m_triggerCount; }
		/*! PreIncrement trigger count. */
		Event& operator++(){ ++m_triggerCount;  return *this; }
		/*! PostIncrement trigger count. */
		Event  operator++(int){
			Event tmp(*this); operator++(); return tmp;}
		/*! PreDecrement trigger count. */
		Event& operator--(){ --m_triggerCount;   return *this; }
		/*! PostDecrement trigger count. */
		Event  operator--(int){
			Event tmp(*this); operator--(); return tmp;}

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>  Event ID and Event Comparisons
		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		/*! Gets the events ID */
		ulong GetID()const{ return c_id; }

		/*! Comparative operator compares the base ID */
		virtual bool operator==(const Event& evnt)
			{ return GetID() == evnt.GetEventID(); }
		/*! Comparative operator compares the base ID */
		virtual bool operator!=(const Event& evnt)
			{ return GetID() != evnt.GetEventID(); }

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>> Event Target Handler Function
		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		/*! Gets the handler function. */
		HandlerFcn	GetHandlerFcn() const { return m_targetFcn; }
		/*! Sets the handler function. */
		void SetTargetHandlerFcn(HandlerFcn targetFcn)
			{ m_targetFcn = targetFcn; }

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>  IOStream Operations
		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

	protected:
		/*! Called by << operator */
		virtual ostream& WriteToStream(ostream& os) const 
			{ return os << c_id; }
		/*! Called by >> operator */
		virtual istream& ParseFromStream(istream& is){ return is; }

	private:
		/*! Override ostream << operator for printing this event to
		console.*/
		friend ostream& operator<<(ostream& os, const Event& evnt){
			 return evnt.WriteToStream(os);}

		/*! Override ostream >> operator to parse commands sent
			to the Event. */
		friend istream& operator>>(istream& is, Event& evnt){
			return evnt.ParseFromStream(is);}

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>  Static Event ID Generator
		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

		/*! Operation called by the constructor to get a
		 generated ID for this instance. */
		static ulong GetEventID(){
			while(!s_idMutex.try_lock()){Pause(1);}
			ulong tmp=s_idGenerator++;s_idMutex.unlock();return tmp;}

		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		>>  Members
		/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/

	protected:
		/*! Optional function handler that takes an Event. */
		HandlerFcn				m_targetFcn;
		/*! Number of times this event has beeen triggered. */
		volatile uint			m_triggerCount;
	private:
		/*! This instances ID */
		const    ulong			c_id;
		/*! Static number used to generate instance IDs. */
		static   ulong			s_idGenerator;
		/*! Mutex used to lock the statis instance ID generator for
		access amongst multiple threads.*/
		static	 boost::mutex	s_idMutex;
	};
	typedef boost::shared_ptr<Event> spEvent;
}

#endif